/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "StockDatabase.h"
#include <QtCore/QTextCodec>
#include "QueryManager.h"
#include "TransactionDatabase.h"

namespace QSThink
{

	StockDatabase::StockDatabase()
	{
		_indexFile=new DBIndexFile();

		_dayIndex=new DBDayIndexFile();

		int days=_dayIndex->getDayCount();

		//read all 

		SectorType sec=Sector_All;
		CultureType cul=Culture_China;
		ExchangeType ex=Exchange_All;

	}

	StockDatabase& StockDatabase::getSingleton()
	{
		static StockDatabase inst;
		return inst;

	}

	bool StockDatabase::persistStockInfo(StockInfo stockInfo)
	{
		int symbol=stockInfo.symbol;
		std::string name=stockInfo.name;
		int index=_indexFile->persist(symbol,name.c_str(),name.length());


		int day=stockInfo.day;
		DBDayFile* dayFile=getDayFile(day);
		dayFile->persit(index,stockInfo);


		return true;
	}

	int StockDatabase::getSymbolIndex( int symbol )
	{
		return _indexFile->getSymbolIndex(symbol);

	}

	void StockDatabase::init()
	{
		loadSymbols(Symbol_Type_ShenZhen);//start with 0
		loadSymbols(Symbol_Type_ShenZhenExt);//start with 3
		loadSymbols(Symbol_Type_ShangHai);//start with 6
		loadSymbolList();
	}

	void StockDatabase::loadSymbolList()
	{
		QFile file("data/symbollist.txt");
		if (!file.open(QFile::ReadOnly)){
			return;
		}

		QStringList words;

		while (!file.atEnd()) {
			QByteArray line = file.readLine();
			if (!line.isEmpty()){//utf8
				QByteArray l=line.trimmed();
				QString word=QTextCodec::codecForName("utf-8")->toUnicode(l);
				words << word;
			}
		}

		file.close();//don't need close if created on stack

		int cnt=words.count();
		for (int i = 0; i < words.count(); ++i) {
			QStringList list=words[i].split("\t");

			if(list.size()<3){
				break;
			}
			QDate date;
			if(list.size()>=6){
				int year=list[3].toInt();
				int month=list[4].toInt();
				int day=list[5].toInt();
				date=QDate(year,month,day);


			}else{
				date=QDate::currentDate().addDays(-1);
			}


			StockSymbol* s=new StockSymbol(list[0],list[1],list[2],date);

			_symbols.push_back(s);

		}

		

	}

	DBDayFile* StockDatabase::getDayFile( int day )
	{
		//find the day data file
		DayDataMap::iterator it= _dataFiles.find(day);
		if(it!=_dataFiles.end()){
			//find
			return it->second;

		}


		DBDayFile* file=new DBDayFile(day);

		_dayIndex->addDay(day);

		_dataFiles.insert(DayDataMap::value_type(day,file));
		return file;

	}

	StockDayInfo* StockDatabase::getStockInfo(int day, int symbol )
	{

		int index=_dayIndex->getDayIndex(day);
		if(index>=0){
			DBDayFile* dayFile=getDayFile(day);
			if(dayFile){
				return dayFile->getStockInfo(symbol);

			}
		}
		return 0;
	}

	std::string StockDatabase::getStockName( int symbol )
	{

		return _indexFile->getStockName(symbol);

	}

	

	void StockDatabase::loadSymbols(StockSymbolType type)
	{
		std::string fileName="";
		switch(type){
			case Symbol_Type_ShangHai:
				fileName="ShangHai.sb";
				break;
			case Symbol_Type_ShenZhen:
				fileName="ShenZhen.sb";
				break;
			case Symbol_Type_ShenZhenExt:
				fileName="ShenZhenExt.sb";
				break;

		}


		FILE* file=fopen(fileName.c_str(),"rb");//wb+ write file

		if(!file){
			return;
		}
		fseek(file,0L,SEEK_END);
		int len=ftell(file);

		char* buf=new char[len];
		fseek(file,0L,SEEK_SET);
		fread(buf,1,len,file);
		fclose(file);


		QString str=QTextCodec::codecForName("GB2312")->toUnicode(buf,len);

		QStringList list=str.split("\n");
		int cnt=list.length();
		for(int i=0;i<cnt;i++){
			QStringList l=list[i].split("\t");
			if(l.length()==2){
				QString symbol=l[0];
				QString name=l[1];

				_symbolToNameMap.insert(StringMap::value_type(symbol,name));
				_nameToSymbolMap.insert(StringMap::value_type(name,symbol));


				switch(type){
				case Symbol_Type_ShangHai:
					_symbolsShangHai.push_back(symbol);
					_namesShangHai.push_back(name);

					//_lookupShangHai.insert(SymbolLookup::value_type(symbol,name));
					break;
				case Symbol_Type_ShenZhen:
					_symbolsShenZhen.push_back(symbol);
					_namesShenZhen.push_back(name);

					//_lookupShenZhen.insert(SymbolLookup::value_type(symbol,name));
					break;
				case Symbol_Type_ShenZhenExt:
					_symbolsShenZhenExt.push_back(symbol);
					_namesShenZhenExt.push_back(name);
					//_lookupShenZhenExt.insert(SymbolLookup::value_type(symbol,name));
					break;
				}


			}
			

		}



	}

	void StockDatabase::startDownload()
	{
		/*
		int days=Utils::getDaysFrom1900()-1;
		int symbol=0;
		int size=_symbolLookup.size();

		SymbolLookup::iterator it=_symbolLookup.begin();
		for(;it!=_symbolLookup.end();++it){
			QString str=it->first;
			bool succes=false;
			int symbol=str.toInt(&succes);

			assert(succes);

			QuerySystem::getSingleton().getDayTransactions(days,symbol);


		}
		*/
		

	}

	int StockDatabase::getSymbolsCount( CultureType cul, ExchangeType ex, SectorType sec )
	{
		switch(cul){
			case Culture_China:
				return getChinaSymbolsCount(ex,sec);
				
		}
		return 0;
	}

	int StockDatabase::getChinaSymbolsCount( ExchangeType ex, SectorType sec )
	{
		int cnt=0;
		switch(ex){

			case Exchange_ShangHai:
				cnt= _symbolsShangHai.size();
				break;
			case Exchange_ShenZhen:

				cnt = _symbolsShenZhen.size();
				cnt+=_symbolsShenZhenExt.size();
				break;
			case Exchange_All:
				cnt = _symbolsShenZhen.size();
				cnt+=_symbolsShenZhenExt.size();
				cnt+=_symbolsShangHai.size();
				break;
		}

		return cnt;
	}

	QString StockDatabase::getName( CultureType cul, ExchangeType ex, SectorType sec ,int index )
	{
		switch(cul){
			case Culture_China:
				return getChinaName(ex,sec,index);

		}
		return "";
	}

	QString StockDatabase::getName( QString symbol )
	{
		StringMap::iterator it=_symbolToNameMap.find(symbol);
		if(it!=_symbolToNameMap.end()){
			return it->second;
		}
		return "";

	}

	

	QString StockDatabase::getSymbol( CultureType cul, ExchangeType ex, SectorType sec ,int index )
	{

		switch(cul){
			case Culture_China:
				return getChinaSymbol(ex,sec,index);

		}

		return "";
	}

	QString StockDatabase::getSymbol( QString name )
	{
		StringMap::iterator it=_nameToSymbolMap.find(name);
		if(it!=_nameToSymbolMap.end()){
			return it->second;
		}
		return "";

	}

	QString StockDatabase::getChinaName( ExchangeType ex, SectorType sec, int index )
	{
		switch(ex){
			case Exchange_ShangHai:
				return getChinaShangHaiName(sec,index);
			case Exchange_ShenZhen:

				return getChinaShenZhenName(sec,index);
			case Exchange_All:
				return getChinaAllName(sec,index);
		}
		return "";

	}

	QString StockDatabase::getChinaSymbol( ExchangeType ex, SectorType sec, int index )
	{
		switch(ex){
			case Exchange_ShangHai:
				return getChinaShangHaiSymbol(sec,index);
			case Exchange_ShenZhen:
				return getChinaShenZhenSymbol(sec,index);
			case Exchange_All:
				return getChinaAllSymbol(sec,index);
		}
		return "";

	}

	QString StockDatabase::getChinaShangHaiName( SectorType sec, int index )
	{
		return _namesShangHai[index];

	}

	QString StockDatabase::getChinaShenZhenName( SectorType sec, int index )
	{
		int cnt=_namesShenZhen.size();
		
		if(index>=cnt){
			return _namesShenZhenExt[index-cnt];
		}

		return _namesShenZhen[index];

	}

	QString StockDatabase::getChinaAllName( SectorType sec, int index )
	{
		int cnt0=_namesShenZhen.size();
		int cnt1=_namesShenZhenExt.size();


		if(index>=cnt0){
			if(index>=cnt0+cnt1){
				return _namesShangHai[index-cnt0-cnt1];
			}
			return _namesShenZhenExt[index-cnt0];
		}

		return _namesShenZhen[index];
	}

	QString StockDatabase::getChinaAllSymbol( SectorType sec, int index )
	{

		int cnt0=_symbolsShenZhen.size();
		int cnt1=_symbolsShenZhenExt.size();


		if(index>=cnt0){
			if(index>=cnt0+cnt1){
				return _symbolsShangHai[index-cnt0-cnt1];
			}
			return _symbolsShenZhenExt[index-cnt0];
		}

		return _symbolsShenZhen[index];

	}

	QString StockDatabase::getChinaShenZhenSymbol( SectorType sec, int index )
	{
		int cnt=_symbolsShenZhen.size();

		if(index>=cnt){
			return _symbolsShenZhenExt[index-cnt];
		}

		return _symbolsShenZhen[index];
	}

	QString StockDatabase::getChinaShangHaiSymbol( SectorType sec, int index )
	{
		return _symbolsShangHai[index];
	}

	bool StockDatabase::hasSymbol( QString symbol )
	{
		StringMap::iterator it=_symbolToNameMap.find(symbol);
		if(it!=_symbolToNameMap.end()){
			return true;
		}
		return false;

	}

	QString StockDatabase::getStockName( QString symbol )
	{

		int cnt=_symbols.size();

		for (int i=0;i<cnt;++i){
			if(_symbols[i]->symbol()==symbol){
				return _symbols[i]->name();
			}
		}

		return "";

	}

	QDate StockDatabase::getStockPublicDate( QString symbol )
	{

		int cnt=_symbols.size();

		for (int i=0;i<cnt;++i){
			if(_symbols[i]->symbol()==symbol){
				return _symbols[i]->datePublic();
			}
		}

		return QDate::currentDate();

	}

	int StockDatabase::getStockPublicDay( QString symbol )
	{
		QDate date=getStockPublicDate(symbol);
		return Utilities::getDaysFrom1900(date);
	}

	StockShareInfo* StockDatabase::getStockShareInfo( QString symbol )
	{
		//Should check whether this symbol is legal
		StockShareInfoMap::iterator it=_shareInfos.find(symbol);
		if(it!=_shareInfos.end()){
			return it->second;//find
		}
		StockShareInfo* info=new StockShareInfo(symbol);
		_shareInfos.insert(StockShareInfoMap::value_type(symbol,info));

		return info;

	}

	double StockDatabase::getStockCapital( QString symbol,QDate date)
	{
		StockShareInfo* info= getStockShareInfo(symbol);
		if(!info){
			return 0;
		}

		qint64 volume=info->getTotalShareCount(date);
		double price=getStockBalancedDayPrice(symbol,date);
		double amount=price*(double)volume;
		return amount;

	}

	double StockDatabase::getStockCapital( QString symbol,int day )
	{
		StockShareInfo* info= getStockShareInfo(symbol);
		if(!info){
			return 0;
		}

		qint64 volume=info->getTotalShareCount(day);
		double price=getStockBalancedDayPrice(symbol,day);
		double amount=price*(double)volume;
		return amount;


	}

	float StockDatabase::getStockBalancedDayPrice( QString symbol, QDate date )
	{
		assert(false);
		throw std::exception("The method or operation is not implemented.");
	}

	float StockDatabase::getStockBalancedDayPrice( QString symbol, int  day )
	{
		Transaction1Day* trans= TransactionDatabase::getSingleton().getDayTransaction(symbol,day);
		return trans->balancePrice();

		
	}

	double StockDatabase::getStockPower( QString symbol,int day )
	{
		StockShareInfo* info= getStockShareInfo(symbol);
		if(!info){
			return 1;
		}

		return info->getPower(day);
	}

	double StockDatabase::getHighestPriceEx( QString symbol,QDate startDate,QDate endDate )
	{
		StockTransactions* trans=TransactionDatabase::getSingleton().getTransactions(symbol);
		return trans->getHighestPriceEx(startDate,endDate);

	}

	double StockDatabase::getLowestPriceEx( QString symbol,QDate startDate,QDate endDate )
	{
		StockTransactions* trans=TransactionDatabase::getSingleton().getTransactions(symbol);
		return trans->getLowestPriceEx(startDate,endDate);
	}

}
